package f.h.dragon.filter;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * DefaultFilterChain: Implementation of <code>f.h.dragon.util.FilterChain<V, R></code> used to manage
 * the execution of a set of filters for a particular V. 
 *
 * @author Wenlong Meng(wenlong.meng@gmail.com)
 * @version 1.0 at 2012/04/01
 * @since 1.0
 */
public class DefaultFilterChain<V, R> implements FilterChain<V, R> {
	
	//local variables
	/**
	 * filters
	 */
	private List<Filter<V, R>> filters = new ArrayList<Filter<V, R>>();
	/**
	 * the index of filters
	 */
	private Map<Long, Integer> indexes = new ConcurrentHashMap<Long, Integer>();
	
	//Constructor
	
	//setter and getter
	/**
	 * add filter into filters
	 * 
	 * @param filter
	 */
	public void addFilter(Filter<V, R> filter){
		this.filters.add(filter);
	}
	
	//Logic
	/**
	 * Causes the first filter in the chain to be invoked, and init/destroy filterChain
	 * 
	 * @param v
	 * @return R
	 */
	public R filter(V v) {
		try{
			init();//init
			return this.doFilter(v);//filter
		}finally{
			destroy();//destroy
		}
	}

	/**
	 * Causes the next filter in the chain to be invoked, or if the calling
	 * filter is the last filter in the chain, causes the resource at the end of
	 * the chain to be invoked.
	 * 
	 * @param v
	 * @return R
	 */
	@Override
	public R doFilter(V v) {
		return this.filters.get(index()).doFilter(v, this);
	}

	/**
	 * init filter chain
	 */
	private void init() {
		this.indexes.put(Thread.currentThread().getId(), 0);
	}

	/**
	 * destroy filter chain
	 */
	private void destroy() {
		this.indexes.remove(Thread.currentThread());
	}
	
	/**
	 * index of the filter in the chain
	 */
	private int index() {
		int i = this.indexes.get(Thread.currentThread()).intValue();
		this.indexes.put(Thread.currentThread().getId(), i + 1);
		return i;
	}
	
}
